/*!
 * \file mapir_test.cc
 *
 * \brief Testing of the MapIR classes
 *
 * \date Started: 8/5/2010
 * \date Last Modified: 8/5/2010
 * \authors Ian Craig
 * \authors Nicholas Jeanette
 *
 * Copyright (c) 2010, Colorado State University <br>
 * All rights reserved. <br>
 * See ../../COPYING for details. <br>
 */

#include <iegenlib/iegenlib.h>
#include <iegen/iegen.h>

#include <gtest/gtest.h>

using iegen::MapIR;
using iegen::DataArray;
using iegen::ERSpec;
using iegen::IndexArray;
using iegen::Statement;
using iegen::AccessRelation;
using iegen::DataDependence;

using iegenlib::EntityExists;
using iegenlib::EntityNotFound;

TEST(MapIRTests, MapIRTest){
  MapIR mymap;
}

TEST(MapIRTests, SymbolicTest){
  Symbolic sym("sym",0,10);
  EXPECT_EQ(sym.getName(), "sym");
  EXPECT_EQ(sym.getLowerBound(), 0);
  EXPECT_EQ(sym.getUpperBound(), 10);

}

TEST(MapIRTests, SymbolicTest1){
  Symbolic sym("sym",4,100);
  EXPECT_EQ(sym.getName(), "sym");
  EXPECT_EQ(sym.getLowerBound(), 4);
  EXPECT_EQ(sym.getUpperBound(), 100);

}

TEST(MapIRTests, DataArrayTest){
  Set s("{[x]: 0<x}");
  DataArray data("0 to x", s);
  EXPECT_EQ(data.get_bound().get_isl(), "{[x] : x-1>=0}");

}

TEST(MapIRTests, DataArrayTest1){
  DataArray data("x to 0", Set("{[x]: 0<x}"));
  EXPECT_EQ(data.get_bound().get_isl(), "{[x] : x-1>=0}");
}

TEST(MapIRTests, DataArrayTest2){
  DataArray data("0 to 5", Set("{[x]: 0<x and x < 5}"));
  EXPECT_EQ(data.get_bound().get_isl(), "{[x] : x-1>=0 and -x+4>=0}");
}

TEST(MapIRTests, ERSpecTestempty){
  ERSpec blah("empty", Set("{[]}"), Set("{[]}"), Relation("{[]->[]}"));
  EXPECT_EQ(blah.get_relation().get_isl(), "{[]->[]}");
  EXPECT_EQ(blah.get_input_bound().get_isl(), "{[]}");
  EXPECT_EQ(blah.get_output_bound().get_isl(), "{[]}");
}

TEST(MapIRTests, ERSpecTestsmall){
  Set x("{[x]}");
  Set y("{[y]}");
  Relation ab("{[a]->[b]}");
  ERSpec small("small", x, y, ab);
  EXPECT_EQ(small.get_relation().get_isl(), "{[a]->[b]}");
  EXPECT_EQ(small.get_input_bound().get_isl(), "{[x]}");
  EXPECT_EQ(small.get_output_bound().get_isl(), "{[y]}");
}

TEST(MapIRTests, ERSpecTestsmall2){
  ERSpec small2("small2", Set("{[x]}"), Set("{[y]}"), Relation("{[a]->[b]}"));
  EXPECT_EQ(small2.get_relation().get_isl(), "{[a]->[b]}");
  EXPECT_EQ(small2.get_input_bound().get_isl(), "{[x]}");
  EXPECT_EQ(small2.get_output_bound().get_isl(), "{[y]}");
}

TEST(MapIRTests, IndexArrayTest){
  IndexArray sim("simple", Set("{[x,y]:x<y}"), Set("{[z]:z>=0}"));
  EXPECT_EQ(sim.get_relation().get_isl(), "{[]->[]}");
  EXPECT_EQ(sim.get_input_bound().get_isl(), "{[x,y] : -x+y-1>=0}");
  EXPECT_EQ(sim.get_output_bound().get_isl(), "{[z] : z>=0}");
}

TEST(MapIRTests, StatementTest){
  MapIR mymap;
  Set s("{[i,j]:0<=i and j<=10}");
  Relation r("{[i,j]->[0,i,1,j,0]}");
  mymap.add_statement("state1","some text", s,r);
  Statement st = mymap.get_statement("state1");
  EXPECT_EQ(st.get_text(), "some text");
  EXPECT_EQ(st.get_itr_space().get_isl(), s.get_isl());
  EXPECT_EQ(st.get_scatter().get_isl(), r.get_isl());
}


TEST(MapIRTests, StatementTestaccess){

    MapIR mymap;
    mymap.add_statement("state0", "a statement", Set("{[z]:z>=0}"), Relation("{[x]->[y]}"));
    mymap.add_access_relation("state0", "acc1", "array1", Relation ("{[x]->[a]}"));
    mymap.add_access_relation("state0", "acc2", "array2", Relation ("{[y]->[b]}"));
    mymap.add_access_relation("state0", "acc3", "array3", Relation ("{[x,y]->[a,b]}"));
    Statement state = mymap.get_statement("state0");
    int s = state.get_access_relations().size();
    EXPECT_EQ(3, s);
}


TEST(MapIRTests, AccessRelationTest){
  AccessRelation ac("acc", "array1", Relation ("{[x,y]->[a,b]}"));
  EXPECT_EQ(ac.get_data_array(),"array1");
  EXPECT_EQ(ac.get_iter_to_data().get_isl(),"{[x,y]->[a,b]}");
}

TEST(MapIRTests, DataDependenceTest){

  DataDependence dd("fad", Relation ("{[x,y]->[a,b]}"));
  EXPECT_EQ(dd.get_dep_rel().get_isl(),"{[x,y]->[a,b]}");
}

TEST(MapIRTest, MAPIRgrabNon){
  try{
    MapIR mymap;
    mymap.add_symbolic("sym1", 1,5);
    mymap.add_symbolic("sym2", 4,5);
    EXPECT_EQ(mymap.get_symbolic("sym3").getLowerBound(),3);
  }catch(EntityNotFound e){
    //std::cout<<e.what()<<std::endl;
    return; //Success!
  }
  ADD_FAILURE()<<"EntityNotFound exception not raised!";
}

TEST(MapIRTest, MAPIRADD1){
  try{
    MapIR mymap;
    mymap.add_data_dep("fad", Relation ("{[x,y]->[a,b]}"));
    EXPECT_EQ(mymap.get_symbolic("fad").getLowerBound(),2);
  }catch(EntityNotFound e){
    //std::cout<<e.what()<<std::endl;
    return; //Success!
  }
  ADD_FAILURE()<<"EntityNotFound exception not raised!";

}

TEST(MapIRTest, MAPIRADD2){
  try{
    MapIR mymap;
    mymap.add_data_dep("fad", Relation ("{[x,y]->[a,b]}"));
    mymap.add_index_array("fad", Set("{[x,y]:x<y}"), Set("{[z]:z>=0}"));
    EXPECT_EQ(mymap.get_index_array("fad").get_input_bound().get_isl(),"{[x,y] : -x+y-1>=0}");
  }
  catch(EntityExists e){
    //std::cout<<e.what()<<std::endl;
    return; //Success!
  }
  ADD_FAILURE()<<"EntityExists exception not raised!";
}

TEST(MapIRTest, MAPIRADDlotsSymbolics){

  MapIR mymap;
  mymap.add_symbolic("sym1", 3, 22);
  mymap.add_symbolic("sym2", 5 ,6);
  mymap.add_symbolic("sym3", 1, 7);
  mymap.add_symbolic("sym4", 4, 23);
  mymap.add_symbolic("sym5", 4, 6);
  EXPECT_EQ(mymap.get_symbolic("sym4").getLowerBound(),4);
  EXPECT_EQ(mymap.get_symbolics().size(),5);


}

TEST(MapIRTest, MAPIRAddDuplicateSymbolic){

  try{
    MapIR mymap;
    mymap.add_symbolic("sym1", 3, 22);
    mymap.add_symbolic("sym1", 5 ,6);
  }
  catch(EntityExists e) {
    return; //Success!
  }

  ADD_FAILURE()<<"EntityExists exception not raised!";
}


TEST(MapIRTest, MAPIRADDlostsDA){

  MapIR mymap;
  mymap.add_data_aray("da1", Set("{[x,y]:x<y}"));
  mymap.add_data_aray("da2", Set("{[x,y]:2x<y}"));
  mymap.add_data_aray("da3", Set("{[x,y]:x<3y}"));
  EXPECT_EQ(mymap.get_data_array("da2").get_bound().get_isl(),"{[x,y] : -2x+y-1>=0}");
  EXPECT_EQ(mymap.get_data_arrays().size(),3);


}


TEST(MapIRTest, MAPIRADDlotsIA){

  MapIR mymap;
  mymap.add_index_array("indexa1", Set("{[x,y]:x<9y}"), Set("{[z]:8z>=0}"));
  mymap.add_index_array("indexa2", Set("{[x,y,z]:x<y}"), Set("{[z,x]:z>=20}"));
  mymap.add_index_array("indexa3", Set("{[x,y]:x<y+4}"), Set("{[z]:2z>=10}"));
  mymap.add_index_array("indexa4", Set("{[x,y,z]:x<y}"), Set("{[z,x]:z+5>=0}"));
  mymap.add_index_array("indexa5", Set("{[x,y]:x<y}"), Set("{[z]:z>=0}"));
  mymap.add_index_array("indexa6", Set("{[x,y,z]:x<y}"), Set("{[z,x]:z>=0}"));
  EXPECT_EQ(mymap.get_index_array("indexa5").get_input_bound().get_isl(),"{[x,y] : -x+y-1>=0}");
  EXPECT_EQ(mymap.get_index_arrays().size(),6);

}

TEST(MapIRTest, MAPIRADDlostES){

  MapIR mymap;
  mymap.add_er_spec("es1", Set("{[]}"), Set("{[]}"), Relation("{[]->[]}"));
  mymap.add_er_spec("es2", Set("{[a]}"), Set("{[d]}"), Relation("{[a]->[d]}"));
  mymap.add_er_spec("es3", Set("{[a,a]}"), Set("{[d,d]}"), Relation("{[d,a]->[a,d]}"));
  mymap.add_er_spec("es4", Set("{[x]:x<y}"), Set("{[y]:y>10}"), Relation("{[x]->[y]}"));
  EXPECT_EQ(mymap.get_er_spec("es1").get_output_bound().get_isl(),"{[]}");
  EXPECT_EQ(mymap.get_er_specs().size(),4);

}

TEST(MapIRTest, MAPIRADDlotsACR){
  try{
    MapIR mymap;
    mymap.add_statement("state0", "a statement", Set("{[z]:z>=0}"), Relation("{[x]->[y]}"));
    mymap.add_access_relation("state0", "acc1", "array1", Relation ("{[x]->[a]}"));
    mymap.add_access_relation("state0", "acc2", "array2", Relation ("{[y]->[b]}"));
    mymap.add_access_relation("state0", "acc3", "array3", Relation ("{[x,y]->[a,b]}"));
    mymap.add_statement("state1", "a statement part 2", Set("{[z]:z>=0}"), Relation("{[x]->[y]}"));
    mymap.add_access_relation("state1", "acc1", "array1", Relation ("{[x]->[a]}"));
    mymap.add_access_relation("state1", "acc2", "array2", Relation ("{[y]->[b]}"));
    mymap.add_access_relation("state1", "acc3", "array3", Relation ("{[x,y]->[a,b]}"));
  }
  catch(EntityExists e){
     //std::cout<<e.what()<<std::endl;
     return; //Success!
  }
  ADD_FAILURE()<<"EntityExists exception not raised!";
}

TEST(MapIRTest, MAPIRADDlotsACR2){
  MapIR mymap;
  mymap.add_statement("state0", "a statement", Set("{[z]:z>=0}"), Relation("{[x]->[y]}"));
  mymap.add_access_relation("state0", "acc1", "array1", Relation ("{[x]->[a]}"));
  mymap.add_access_relation("state0", "acc2", "array2", Relation ("{[y]->[b]}"));
  mymap.add_access_relation("state0", "acc3", "array3", Relation ("{[x,y]->[a,b]}"));
  mymap.add_statement("state1", "a statement part 2", Set("{[z1]:z>=0}"), Relation("{[x1]->[y1]}"));
  mymap.add_access_relation("state1", "acc1a", "array1a", Relation ("{[xa]->[aa]}"));
  mymap.add_access_relation("state1", "acc2a", "array2a", Relation ("{[ya]->[ba]}"));
  mymap.add_access_relation("state1", "acc3a", "array3a", Relation ("{[xa,ya]->[aa,ba]}"));
  Statement state = mymap.get_statement("state0");
  int s = state.get_access_relations().size();
  EXPECT_EQ(3, s);
//  state = mymap.get_statement("state1");
//  map<string, AccessRelation> ACR = state.get_access_relations();
//  AccessRelation A1 = ACR.find("acc1a")->second;
//  EXPECT_EQ(A1.get_data_array(), "array1a");

}


TEST(MapIRTest, MAPIRADDlotsDD){
  MapIR mymap;
  mymap.add_data_dep("datadep1", Relation ("{[x,y]->[a,b]}"));
  mymap.add_data_dep("datadep2", Relation ("{[x]->[a]}"));
  mymap.add_data_dep("datadep3", Relation ("{[x,y]->[a,b]}"));
  mymap.add_data_dep("datadep4", Relation ("{[x]->[a]}"));
  mymap.add_data_dep("datadep5", Relation ("{[x,y]->[a,b]}"));
  mymap.add_data_dep("datadep6", Relation ("{[x]->[a]}"));
  EXPECT_EQ(mymap.get_data_dep("datadep1").get_dep_rel().get_isl(),"{[x,y]->[a,b]}");
}


TEST(MapIRTest, MAPIRADD4){
  try{
    MapIR mymap;
    mymap.add_data_dep("datadep1", Relation ("{[x,y]->[a,b]}"));
    mymap.add_index_array("indexa1", Set("{[x,y]:x<y}"), Set("{[z]:z>=0}"));
    mymap.add_data_dep("datadep2", Relation ("{[x]->[a]}"));
    mymap.add_index_array("indexa2", Set("{[x,y,z]:x<y}"), Set("{[z,x]:z>=0}"));
    mymap.add_er_spec("small2", Set("{[x]}"), Set("{[y]}"), Relation("{[a]->[b]}"));
    EXPECT_EQ(mymap.get_index_array("datadep1").get_input_bound().get_isl(),"{[x,y] : -x+y-1>=0}");
  }catch(EntityNotFound e){
    //std::cout<<e.what()<<std::endl;
    return; //Success!
  }
  ADD_FAILURE()<<"EntityExists exception not raised!";
}

TEST(MapIRTest, MAPIRADDlotsACR3){
  try{
  MapIR mymap;
  mymap.add_statement("state0", "a statement", Set("{[z]:z>=0}"), Relation("{[x]->[y]}"));
  mymap.add_access_relation("state0", "acc1", "array1", Relation ("{[x]->[a]}"));
  mymap.add_access_relation("state0", "acc2", "array2", Relation ("{[y]->[b]}"));
  mymap.add_access_relation("state0", "acc3", "array3", Relation ("{[x,y]->[a,b]}"));
  mymap.add_access_relation("state1", "acc1a", "array1a", Relation ("{[xa]->[aa]}"));
  mymap.add_access_relation("state1", "acc2a", "array2a", Relation ("{[ya]->[ba]}"));
  mymap.add_access_relation("state1", "acc3a", "array3a", Relation ("{[xa,ya]->[aa,ba]}"));

  }catch(EntityNotFound e){
    //std::cout<<e.what()<<std::endl;
    return; //Success!
  }

}

TEST(MapIRTest, MAPIRADDlotsACR4){
  try{
  MapIR mymap;
//  Statement state1("state1", "a statement", Set("{[z]:z>=0}"), Relation("{[x]->[y]}"));
//  state1.add_access_relation("acc3", "array3", Relation ("{[x,y]->[a,b]}"));
  mymap.add_statement("state0", "a statement", Set("{[z]:z>=0}"), Relation("{[x]->[y]}"));
  mymap.add_access_relation("state0", "acc1", "array1", Relation ("{[x]->[a]}"));
  mymap.add_access_relation("state0", "acc2", "array2", Relation ("{[y]->[b]}"));
  mymap.add_access_relation("state0", "acc3", "array3", Relation ("{[x,y]->[a,b]}"));
  Statement state0 = mymap.get_statement("state0");


  }catch(EntityExists e){
    //std::cout<<e.what()<<std::endl;
    return; //Success!
  }

}
